今天要來教大家簡單起一個 prisma 專案讓大家感受一下什麼叫做 type safe 的 ORM ~
先產生一個資料夾,然後進入 folder
> mkdir hello-prisma
> cd hello-prisma
初始化 package 然後安裝相關 lib
> npm init -y
> npm install typescript ts-node @types/node --save-dev
初始化 typescript setting
> npx tsc --init
然後 install prisma
> npm install prisma --save-dev
最後 prisma 也需要做初始化,這邊選用 sqlite 當作我們的 datasource
> npx prisma init --datasource-provider sqlite
上面的 cli 會自動幫我們產生 prisma 的資料夾,提供我們訂定 model 的 schema ,然後因為我們是使用 SQL lite 也會自動幫我們設定好 SQLite 的 database
之後我們先到 prisma/schema.prisma 中去定義我們的 Model
// prisma/schema.prisma
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
}
Models 在 prisma 中有以下的功用:
database 中的 table
prisma client 提供 code generate 的基礎配置別忘記每當我們有新增 Model 時候要記得跑一次 Migration 不然 Database 並不會知道我們定好的 Model
> npx prisma migrate dev --name init
migration cli 做了三件事:
SQL migration file 在 prisma/migrations 資料夾。SQL migration 到 database。prisma generate 針對 model 去產生對應的 prisma client api 取使用,同時自動產生 type。
你會看到 migration 自動執行 prisma generate 就是會在你的 node_modules 透過 code generate 產生對應 prisma client 的 inteface 以及各種 Model 的 type ,這也是為什麼 prisma 可以做到 type safe 的原因,所以如果你的 node_modules 不小心刪掉,記得要重新跑一下 prisma generate 喔~

然後 prisma 也會多一個 .env 去 link 你的 dataSource ,那因為我們是用 sqlite prisma 會自動幫我們產生 dev.db 所以這邊的 DATABASE_URL 會 link 到 dev.db 位置
// .env
DATABASE_URL="file:./dev.db"
首先先創建 index.ts 然後使用 PrismaClient 去創建一個 prisma client 的 instance ,然後每次當我們使用 PrismaClient 背後都會自動起一個 connection 到 database ,所以記得要在 than 或是 error 時候去釋放 connection 喔~
// index.ts
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
// ... you will write your Prisma Client queries here
}
main()
.then(async () => {
await prisma.$disconnect()
})
.catch(async (e) => {
console.error(e)
await prisma.$disconnect()
process.exit(1)
})
那因為 prisma client 有自動幫我們 code generate 了,所以 user Model 也會自動有對應欄位的 type。
然後至邊眼睛很利的小夥伴應該看到,我們這邊使用 faker 這套 lib 去自動幫我們產生 mock data ,對於不想思考內容的朋友應該有方長大的幫助~有興趣的讀者可以自行玩玩看~ Faker
import { PrismaClient } from "@prisma/client";
import { faker } from '@faker-js/faker';
const prismaClient = new PrismaClient()
async function main() {
const user = await prismaClient.user.create({
data: {
name: faker.person.fullName(),
email: faker.internet.email()
}
})
console.log(user)
}
然後直接 run 我們的 index.ts
> npx ts-node index.ts
如此就成功 create 一筆 record 了~
{ id: 1, email: 'alice@prisma.io', name: 'Alice' }
現在成功寫入 Data 接下來就教大家怎麼 get,我們直接改用其他 api findMany 這樣就可以拿到全部的 users 內容了。
async function main() {
const users = await prisma.user.findMany()
console.log(users)
}
這樣我們就成功拿到資料拉~
[{ id: 1, email: 'alice@prisma.io', name: 'Alice' }]
另一個 prisma 的特點是,他提供關聯式的用法,還記得我們的 Post 是關聯到 User 的嗎,接下來就教讀者如何在 create 的時候去 relaction 其他的 Model
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
}
這邊稍微改寫一下我們 create 的使用方式,如以下的 posts 因為他跟 User 是一對多的關係,所以我們在 User 的 create data 欄位中 posts 是可以 create 多筆的。
async function main() {
const user = await prisma.user.create({
data: {
name: 'Bob',
email: 'bob@prisma.io',
posts: {
create: [
{
title: 'Hello World',
published: true
},
{
title: 'My second post',
content: 'This is still a draft'
}
],
},
},
})
console.log(user)
}
上面的 create 是在於 User 跟 Post 都沒有資料情況下一邊 create 一邊做關聯的,如果 posts 已經存在可以使用 connect 然後對應到 postId
const users = await prismaClient.user.create({
data: {
name: faker.person.fullName(),
email: faker.internet.email(),
posts: {
connect: [{ id: 1 }, { id: 2 }]
}
}
})
這時你會發現並沒有 log 跟 user 有關聯的 post data,那是因為 prisma 預設只要跟 relaction 有關的 query ,如果不是透過 include 的方式,並不會 log 出來,接下來我們就來學習 include 的用法。
{ id: 2, email: 'bob@prisma.io', name: 'Bob' }
我們先修改之前的 read ,現在只需要加上 include 然後告訴 prisma 哪些 relaction 的 Model 需要顯示。
async function main() {
const usersWithPosts = await prisma.user.findMany({
include: {
posts: true,
},
})
console.dir(usersWithPosts, { depth: null })
}
執行 index.ts 後你就會看到完整的內容了
[
{ id: 1, email: 'alice@prisma.io', name: 'Alice', posts: [] },
{
id: 2,
email: 'bob@prisma.io',
name: 'Bob',
posts: [
{
id: 1,
title: 'Hello World',
content: null,
published: true,
authorId: 2
},
{
id: 2,
title: 'My second post',
content: 'This is still a draft',
published: false,
authorId: 2
}
]
}
]
補充一個比較特別的是如果只是需要隱藏特定的 fields 可以用 select 的語法,甚至也可以用到特定的關聯式資料
const usersWithPosts = await prismaClient.user.findMany({
select: {
id: true,
email: true,
name: true,
posts: {
select: {
id: true,
title: true
}
}
}
})
結果大概是這個樣子
[
{
id: 2,
email: "Jalen_Padberg59@hotmail.com",
name: "Everett Graham",
posts: [
{
id: 1,
title: "amo-verto-voco",
}, {
id: 2,
title: "demo-uxor-corona",
}
],
}
]
今天內容大致到這邊感謝各位讀者耐心的觀看~
✅ 前端社群 :
https://lihi3.cc/kBe0Y